using System;
using System.Collections.Generic;
using NServiceBus.Management.ManagementService;
using NServiceBus.Management.ManagementService.MessageHandlers;
using NServiceBus.Management.ManagementService.Messages;
using NServiceBus.Management.Messages.EndpointControl;
using NServiceBus.Management.Messages.Statistics;
using NServiceBus.Management.Messages.Status;
using NServiceBus.Management.UnitTests.Messages;
using NUnit.Framework;
using Rhino.Mocks;

namespace NServiceBus.Management.UnitTests.ManagementService
{
    [TestFixture]
    public class The_management_service_should
    {
        [Test]
        public void Register_endpoint_when_onlinemessage_is_received()
        {
            var service = new Management.ManagementService.ManagementService();
            var handler = new StatusMessageHandler{ Manager = service };

            //register new endpoint
            handler.Handle(new OnlineMessage(){EndpointId="Test"});

            Assert.AreEqual(service.GetCurrentEndpoints().Count, 1);
            
            //register duplucate, should be ok,Just a warning
            handler.Handle(new OnlineMessage() { EndpointId = "Test" });

            Assert.AreEqual(service.GetCurrentEndpoints().Count ,1);
        }

        [Test]
        public void Ping_endpoints_periodically()
        {
            var bus = MockRepository.GenerateStub<IBus>();
            var service = new Management.ManagementService.ManagementService(){Bus=bus};

            SystemTime.Now = () => new DateTime(2008, 1, 1);

            string adress = "test@localhost";
            service.RegisterNewEndpoint("test",adress);

            SystemTime.Now = () => new DateTime(2008, 1, 2);

            service.PingEndpointsOlderThan(10);

            bus.AssertWasCalled(x => x.Send(Arg<string>.Matches(p0 => p0 == adress),
                                       Arg<IMessage[]>.Matches(
                                           p => (p[0]) is PingCommand)));

        }

        [Test]
        public void Update_statustime_when_ping_response_is_received()
        {
            var service = new Management.ManagementService.ManagementService();
            var handler = new StatusMessageHandler() { Manager = service };

            SystemTime.Now = () => new DateTime(2008, 1, 1);

            service.RegisterNewEndpoint("test1", "");

            SystemTime.Now = () => new DateTime(2008, 1, 2);

            //register new endpoint
            handler.Handle(new PingResponse(){EndpointId = "test1"});

            Assert.AreEqual(service.GetCurrentEndpoints()[0].StatusTime, new DateTime(2008, 1, 2));
        
        }

        [Test]
        public void Remove_endpoints_that_dont_respond_to_ping()
        {
            var service = new Management.ManagementService.ManagementService();

            SystemTime.Now = () => new DateTime(2008, 1, 1);

            service.RegisterNewEndpoint("test1", "");

            SystemTime.Now = () => new DateTime(2008, 1, 2);

            service.RegisterNewEndpoint("test2", "");

            //endpoint "test1" is now to old and should be removed
            service.RemoveEndpointsOlderThan(60*60);

            Assert.AreEqual(service.GetCurrentEndpoints().Count, 1);
            Assert.AreEqual(service.GetCurrentEndpoints()[0].Id, "test2");
        }


        [Test]
        public void Manage_statuses()
        {
            var service = new Management.ManagementService.ManagementService();

            service.UpdateEndpointStatus(new StatusMessage { EndpointId = "1" });

            Assert.AreEqual(service.EndpointStatuses.Count, 1);
            Assert.AreEqual(service.EndpointStatuses[0].EndpointId, "1");

            //add duplicate
            service.UpdateEndpointStatus(new StatusMessage { EndpointId = "1" });
            Assert.AreEqual(service.EndpointStatuses.Count, 1);


            //add another
            service.UpdateEndpointStatus(new StatusMessage { EndpointId = "2" });
            Assert.AreEqual(service.EndpointStatuses.Count, 2);

        }
        [Test]
        public void Add_and_get_statistics_for_number_of_messages()
        {
            var startTime = DateTime.Today;

            IManagementService service = new Management.ManagementService.ManagementService();

            service.AddStatistics(new NumberOfMessagesDatapoint { Endpoint ="TestEndpoint",Type =typeof(TestMessage), Time = startTime,Value=3});
            service.AddStatistics(new NumberOfMessagesDatapoint { Endpoint = "TestEndpoint", Type = typeof(TestMessage), Time = startTime.AddMinutes(1), Value = 3 });
            service.AddStatistics(new NumberOfMessagesDatapoint { Endpoint = "TestEndpoint2", Type = typeof(TestMessage), Time = startTime.AddMinutes(1), Value = 3 });
            service.AddStatistics(new NumberOfMessagesDatapoint { Endpoint = "TestEndpoint", Type = typeof(OnlineMessage), Time = startTime.AddMinutes(1), Value = 3 });

            
            Assert.AreEqual(2, service.GetNumberOfMessagesFor("TestEndpoint", typeof(TestMessage), startTime, startTime.AddHours(1)).Count);
            Assert.AreEqual(1, service.GetNumberOfMessagesFor("TestEndpoint", typeof(TestMessage), startTime, startTime.AddSeconds(1)).Count);
            Assert.AreEqual(0, service.GetNumberOfMessagesFor("TestEndpoint", typeof(TestMessage), startTime.AddMinutes(-1), startTime).Count);

        }
        
        [Test]
        public void Handle_request_for_number_of_messages_statistics()
        {
            var bus = MockRepository.GenerateStub<IBus>();
            string endpoint = "TestEndpoint";

            var to = DateTime.Now;
            var from = to.AddDays(1);
            
            var service = MockRepository.GenerateStub<IManagementService>();

            service.Stub(x => x.GetNumberOfMessagesFor(endpoint, typeof(TestMessage), from, to))
                            .Return(new List<NumberOfMessagesDatapoint>{new NumberOfMessagesDatapoint(),new NumberOfMessagesDatapoint()});

            IMessageHandler<GetStatisticsRequest> handler = new GetStatisticsRequestHandler
                                                                         {
                                                                             ManagementService = service,
                                                                             Bus = bus
                                                                         };
            var request = new GetStatisticsRequest
                              {
                                  MessageType = typeof(TestMessage),
                                  From = from,
                                  To =to,
                                  Endpoint = endpoint
                              };

            handler.Handle(request);


            bus.AssertWasCalled(x => x.Reply(
                                       Arg<IMessage[]>.Matches(
                                           p => ((GetStatisticsReply)p[0]).DataPoints.Count== 2)));

        }
    }
}